const crypto = require('./crypto.js');

class AliyunIoTMQTT {
  constructor() {
    this.config = {
      productKey: "k1s4giENrlZ",
      deviceName: "wxxcx", 
      deviceSecret: "9df991d8f792a80735d6cb09ddab198d",
      regionId: "cn-shanghai",
      mqttHostUrl: "iot-06z00ehxjlhnidg.mqtt.iothub.aliyuncs.com",
      port: 1883
    };
    
    this.topics = {
      propertyPost: `/sys/${this.config.productKey}/${this.config.deviceName}/thing/event/property/post`,
      propertySet: `/sys/${this.config.productKey}/${this.config.deviceName}/thing/service/property/set`,
      propertySetReply: `/sys/${this.config.productKey}/${this.config.deviceName}/thing/service/property/set_reply`
    };
    
    this.socketTask = null;
    this.isConnected = false;
    this.messageId = 1;
    this.callbacks = new Map();
    this.subscriptions = new Map();
    
    // 回调函数
    this.connectionCallback = null;
    this.dataCallback = null;
    
    // 心跳相关
    this.keepAliveInterval = null;
    this.keepAliveTime = 240; // 240秒心跳间隔（小于Keep Alive时间）
    this.lastPingTime = 0;
    this.pingTimeout = null;
    
    // 重连相关
    this.reconnectInterval = null;
    this.reconnectDelay = 5000; // 5秒重连延迟
    this.maxReconnectAttempts = 10;
    this.reconnectAttempts = 0;
    this.autoReconnect = true;
  }

  // 设置连接状态回调
  setConnectionCallback(callback) {
    this.connectionCallback = callback;
  }

  // 设置数据接收回调
  setDataCallback(callback) {
    this.dataCallback = callback;
  }

  generateAuth() {
    // 使用当前时间戳确保一致性
    const timestamp = 1749394091290;
    const clientId = `k1s4giENrlZ.wxxcx|securemode=2,signmethod=hmacsha256,timestamp=${timestamp}|`;
    const username = `wxxcx&k1s4giENrlZ`;
    
    // 按照阿里云文档的签名算法：按字典排序拼接参数
    // 必填参数：deviceName, productKey
    // 可选参数：clientId, timestamp (如果传入必须与mqttClientId中设置相同)
    const content = `clientId${this.config.productKey}.${this.config.deviceName}deviceName${this.config.deviceName}productKey${this.config.productKey}timestamp${timestamp}`;
    const password = `b6d3011b11eba39cd83091973025901e4dc23e556605c279070613432dbd01c6`;
    
    console.log('MQTT WebSocket认证参数:', {
      clientId,
      username,
      password,
      timestamp,
      content
    });
    
    return {
      clientId,
      username,
      password,
      timestamp
    };
  }

  connect() {
    return new Promise((resolve, reject) => {
      try {
        // 如果已经连接，直接返回成功
        if (this.isConnected && this.socketTask) {
          console.log('MQTT已连接，跳过重复连接');
          resolve();
          return;
        }
        
        // 如果正在连接中，等待现有连接完成
        if (this.callbacks.has('connect')) {
          console.log('MQTT正在连接中，等待现有连接完成');
          const existingCallback = this.callbacks.get('connect');
          existingCallback.resolve = resolve;
          existingCallback.reject = reject;
          return;
        }
        
        const auth = this.generateAuth();
        
        // 阿里云IoT WebSocket连接URL格式 (使用443端口)
        const wsUrl = `wss://${this.config.mqttHostUrl}:443/mqtt`;
        console.log('连接WebSocket URL:', wsUrl);
        
        this.socketTask = wx.connectSocket({
          url: wsUrl,
          protocols: ['mqtt'],
          success: () => {
            console.log('WebSocket连接成功');
          },
          fail: (error) => {
            console.error('WebSocket连接失败:', error);
            reject(error);
          }
        });

        this.socketTask.onOpen(() => {
          console.log('WebSocket已打开，开始MQTT连接...');
          this.sendConnectPacket(auth);
        });

        this.socketTask.onMessage((res) => {
          this.handleMessage(res.data);
        });

        this.socketTask.onClose((res) => {
          console.log('WebSocket连接已关闭:', res);
          this.isConnected = false;
          this.stopHeartbeat();
          if (this.connectionCallback) {
            this.connectionCallback(false);
          }
          
          // 触发自动重连
          if (this.autoReconnect) {
            this.scheduleReconnect();
          }
        });

        this.socketTask.onError((error) => {
          console.error('WebSocket错误:', error);
          this.isConnected = false;
          this.stopHeartbeat();
          if (this.connectionCallback) {
            this.connectionCallback(false);
          }
          
          // 触发自动重连
          if (this.autoReconnect) {
            this.scheduleReconnect();
          }
          reject(error);
        });

        this.callbacks.set('connect', { resolve, reject });

      } catch (error) {
        console.error('连接初始化失败:', error);
        reject(error);
      }
    });
  }

  sendConnectPacket(auth) {
    console.log('发送MQTT CONNECT包:', auth);
    
    const protocolName = 'MQTT';
    const protocolLevel = 0x04;
    const connectFlags = 0xC2; // Clean session + Username + Password
    const keepAlive = 300; // 阿里云建议300秒以上
    
    // 计算正确的剩余长度
    const variableHeaderLength = 2 + protocolName.length + 1 + 1 + 2; // 协议名长度 + 协议名 + 协议级别 + 连接标志 + 保持连接
    const payloadLength = 2 + auth.clientId.length + 2 + auth.username.length + 2 + auth.password.length;
    const remainingLength = variableHeaderLength + payloadLength;
    
    console.log('MQTT包长度计算:', {
      variableHeaderLength,
      payloadLength,
      remainingLength,
      clientIdLength: auth.clientId.length,
      usernameLength: auth.username.length,
      passwordLength: auth.password.length
    });
    
    let packet = new Uint8Array(1024);
    let pos = 0;
    
    // 固定头部
    packet[pos++] = 0x10; // CONNECT消息类型
    
    // 剩余长度编码（可变长度）
    if (remainingLength < 128) {
      packet[pos++] = remainingLength;
    } else {
      packet[pos++] = (remainingLength % 128) | 0x80;
      packet[pos++] = Math.floor(remainingLength / 128);
    }
    
    // 可变头部
    // 协议名长度
    packet[pos++] = (protocolName.length >> 8) & 0xFF;
    packet[pos++] = protocolName.length & 0xFF;
    // 协议名
    for (let i = 0; i < protocolName.length; i++) {
      packet[pos++] = protocolName.charCodeAt(i);
    }
    // 协议级别
    packet[pos++] = protocolLevel;
    // 连接标志
    packet[pos++] = connectFlags;
    // 保持连接时间
    packet[pos++] = (keepAlive >> 8) & 0xFF;
    packet[pos++] = keepAlive & 0xFF;
    
    // 载荷
    // 客户端ID
    packet[pos++] = (auth.clientId.length >> 8) & 0xFF;
    packet[pos++] = auth.clientId.length & 0xFF;
    for (let i = 0; i < auth.clientId.length; i++) {
      packet[pos++] = auth.clientId.charCodeAt(i);
    }
    
    // 用户名
    packet[pos++] = (auth.username.length >> 8) & 0xFF;
    packet[pos++] = auth.username.length & 0xFF;
    for (let i = 0; i < auth.username.length; i++) {
      packet[pos++] = auth.username.charCodeAt(i);
    }
    
    // 密码
    packet[pos++] = (auth.password.length >> 8) & 0xFF;
    packet[pos++] = auth.password.length & 0xFF;
    for (let i = 0; i < auth.password.length; i++) {
      packet[pos++] = auth.password.charCodeAt(i);
    }
    
    console.log('MQTT CONNECT包大小:', pos);
    
    this.socketTask.send({
      data: packet.slice(0, pos).buffer
    });
  }

  handleMessage(data) {
    const packet = new Uint8Array(data);
    const messageType = (packet[0] >> 4) & 0x0F;
    
    switch (messageType) {
      case 2:
        this.handleConnAck(packet);
        break;
      case 3:
        this.handlePublish(packet);
        break;
      case 4:
        this.handlePubAck(packet);
        break;
      case 9:
        this.handleSubAck(packet);
        break;
      case 13:
        this.handlePingResp(packet);
        break;
      default:
        console.log('未处理的MQTT消息类型:', messageType);
    }
  }

  handleConnAck(packet) {
    const returnCode = packet[3];
    const errorMessages = {
      0: '连接已接受',
      1: '连接被拒绝，不支持的协议版本',
      2: '连接被拒绝，客户端标识符不合法',
      3: '连接被拒绝，服务器不可用',
      4: '连接被拒绝，用户名或密码错误',
      5: '连接被拒绝，未授权'
    };
    
    console.log('收到CONNACK:', {
      returnCode,
      message: errorMessages[returnCode] || `未知错误码: ${returnCode}`
    });
    
    if (returnCode === 0) {
      console.log('MQTT连接成功');
      this.isConnected = true;
      this.reconnectAttempts = 0; // 重置重连计数
      this.subscribeToTopics();
      this.startHeartbeat(); // 启动心跳
      
      // 通知连接状态
      if (this.connectionCallback) {
        this.connectionCallback(true);
      }
      
      const callback = this.callbacks.get('connect');
      if (callback) {
        callback.resolve();
        this.callbacks.delete('connect');
      }
    } else {
      const errorMsg = errorMessages[returnCode] || `未知错误码: ${returnCode}`;
      console.error('MQTT连接失败:', errorMsg);
      
      const callback = this.callbacks.get('connect');
      if (callback) {
        callback.reject(new Error(`连接失败: ${errorMsg}`));
        this.callbacks.delete('connect');
      }
    }
  }

  handlePublish(packet) {
    let pos = 1; // 跳过固定头部的第一个字节
    
    // 解析剩余长度（可变长度编码）
    let remainingLength = 0;
    let multiplier = 1;
    let byte;
    do {
      if (pos >= packet.length) {
        console.error('MQTT包长度不足');
        return;
      }
      byte = packet[pos++];
      remainingLength += (byte & 0x7F) * multiplier;
      multiplier *= 128;
    } while ((byte & 0x80) !== 0);

    console.log('MQTT PUBLISH包剩余长度:', remainingLength);
    
    // 解析主题长度
    if (pos + 2 > packet.length) {
      console.error('MQTT包主题长度不足');
      return;
    }
    const topicLength = (packet[pos] << 8) | packet[pos + 1];
    pos += 2;
    
    // 验证主题长度
    if (pos + topicLength > packet.length) {
      console.error('MQTT包主题数据不足');
      return;
    }
    
    // 解析主题
    const topicBytes = packet.slice(pos, pos + topicLength);
    const topic = this.bytesToString(topicBytes);
    pos += topicLength;
    
    const qos = (packet[0] >> 1) & 0x03;
    if (qos > 0) {
      if (pos + 2 > packet.length) {
        console.error('MQTT包消息ID不足');
        return;
      }
      pos += 2; // 跳过消息ID
    }
    
    // 解析载荷
    const payloadBytes = packet.slice(pos);
    const payload = this.bytesToString(payloadBytes);
    
    console.log('收到MQTT消息:', topic, '长度:', payloadBytes.length);
    console.log('原始数据:', payload);
    
    try {
      // 清理可能的无效字符
      const cleanPayload = payload.replace(/\0/g, '').trim();
      if (cleanPayload) {
        const data = JSON.parse(cleanPayload);
        this.handleIncomingMessage(topic, data);
      } else {
        console.warn('收到空的payload');
      }
    } catch (error) {
      console.error('解析MQTT消息失败:', error);
      console.error('原始payload:', payload);
      console.error('payload字节长度:', payloadBytes.length);
      console.error('payload前20字节:', Array.from(payloadBytes.slice(0, 20)));
    }
  }

  // 将字节数组转换为字符串的安全方法
  bytesToString(bytes) {
    try {
      // 方法1: 使用TextDecoder (推荐)
      if (typeof TextDecoder !== 'undefined') {
        const decoder = new TextDecoder('utf-8');
        return decoder.decode(bytes);
      }
      
      // 方法2: 分块处理，避免参数过多的问题
      let result = '';
      const chunkSize = 1024;
      for (let i = 0; i < bytes.length; i += chunkSize) {
        const chunk = bytes.slice(i, i + chunkSize);
        result += String.fromCharCode.apply(null, chunk);
      }
      return result;
    } catch (error) {
      console.error('字节转字符串失败:', error);
      // 回退方案：逐字节转换
      let result = '';
      for (let i = 0; i < bytes.length; i++) {
        result += String.fromCharCode(bytes[i]);
      }
      return result;
    }
  }

  handleIncomingMessage(topic, data) {
    console.log('处理收到的消息:', {
      topic,
      dataType: typeof data,
      method: data.method,
      hasParams: !!data.params,
      hasItems: !!data.items
    });
    
    console.log('主题匹配检查:', {
      received: topic,
      expectedPropertySet: this.topics.propertySet,
      expectedPropertyPost: this.topics.propertyPost,
      isPropertySet: topic === this.topics.propertySet,
      isPropertyPost: topic === this.topics.propertyPost
    });

    if (topic === this.topics.propertySet) {
      // 这是属性设置命令，但数据格式是阿里云的items格式
      this.handlePropertySet(data);
      
      // 同时也作为传感器数据处理
      if (data.items && this.dataCallback) {
        console.log('解析阿里云IoT数据格式:', data.items);
        
        // 将阿里云格式转换为我们的格式
        const sensorData = {};
        Object.keys(data.items).forEach(key => {
          const item = data.items[key];
          if (item && typeof item.value !== 'undefined') {
            sensorData[key] = item.value;
          }
        });
        
        console.log('转换后的传感器数据:', sensorData);
        this.dataCallback(sensorData);
      }
    } else if (topic === this.topics.propertyPost || data.method === 'thing.event.property.post') {
      // 传感器数据上传
      console.log('收到传感器数据:', data);
      
      if (this.dataCallback && data.params) {
        console.log('转发传感器数据:', data.params);
        this.dataCallback(data.params);
      }
    } else {
      console.log('处理其他类型消息:', data);
    }
  }

  handlePropertySet(data) {
    console.log('收到属性设置命令:', data);
    
    // 处理阿里云IoT格式的数据
    if (data.items) {
      console.log('收到阿里云IoT格式的传感器数据');
    }
    
    // 发送回复（使用阿里云要求的格式）
    if (data.requestId) {
      this.sendPropertySetReply(data.requestId, 200, 'success');
    } else if (data.id) {
      this.sendPropertySetReply(data.id, 200, 'success');
    }
  }

  sendPropertySetReply(id, code, message) {
    const replyData = {
      id: id,
      code: code,
      data: {},
      message: message
    };
    
    this.publish(this.topics.propertySetReply, JSON.stringify(replyData));
  }

  subscribeToTopics() {
    this.subscribe(this.topics.propertySet, (data) => {
      console.log('订阅主题收到数据:', data);
    });
  }

  subscribe(topic, callback) {
    const messageId = this.messageId++;
    
    let packet = new Uint8Array(256);
    let pos = 0;
    
    packet[pos++] = 0x82;
    let remainingLength = 2 + 2 + topic.length + 1;
    packet[pos++] = remainingLength;
    
    packet[pos++] = (messageId >> 8) & 0xFF;
    packet[pos++] = messageId & 0xFF;
    
    packet[pos++] = (topic.length >> 8) & 0xFF;
    packet[pos++] = topic.length & 0xFF;
    for (let i = 0; i < topic.length; i++) {
      packet[pos++] = topic.charCodeAt(i);
    }
    
    packet[pos++] = 0x01;
    
    this.subscriptions.set(topic, callback);
    
    this.socketTask.send({
      data: packet.slice(0, pos).buffer
    });
    
    console.log('订阅主题:', topic);
  }

  handleSubAck(packet) {
    console.log('订阅确认收到');
  }

  handlePubAck(packet) {
    console.log('发布确认收到');
  }

  publish(topic, payload) {
    if (!this.isConnected || !this.socketTask) {
      console.error('MQTT未连接，无法发布消息', {
        isConnected: this.isConnected,
        hasSocket: !!this.socketTask
      });
      return;
    }
    
    const messageId = this.messageId++;
    
    let packet = new Uint8Array(2048); // 增大缓冲区
    let pos = 0;
    
    // PUBLISH消息类型 + QoS1
    packet[pos++] = 0x32;
    
    // 计算剩余长度
    let remainingLength = 2 + topic.length + 2 + payload.length;
    
    // 编码剩余长度（可变长度编码）
    if (remainingLength < 128) {
      packet[pos++] = remainingLength;
    } else if (remainingLength < 16384) {
      packet[pos++] = (remainingLength % 128) | 0x80;
      packet[pos++] = Math.floor(remainingLength / 128);
    } else {
      // 支持更大的包
      packet[pos++] = (remainingLength % 128) | 0x80;
      remainingLength = Math.floor(remainingLength / 128);
      packet[pos++] = (remainingLength % 128) | 0x80;
      packet[pos++] = Math.floor(remainingLength / 128);
    }
    
    // 主题长度和主题
    packet[pos++] = (topic.length >> 8) & 0xFF;
    packet[pos++] = topic.length & 0xFF;
    for (let i = 0; i < topic.length; i++) {
      packet[pos++] = topic.charCodeAt(i);
    }
    
    // 消息ID（QoS1需要）
    packet[pos++] = (messageId >> 8) & 0xFF;
    packet[pos++] = messageId & 0xFF;
    
    // 载荷
    for (let i = 0; i < payload.length; i++) {
      packet[pos++] = payload.charCodeAt(i);
    }
    
    console.log('发布消息到主题:', topic, '包大小:', pos, '载荷长度:', payload.length);
    
    this.socketTask.send({
      data: packet.slice(0, pos).buffer
    });
  }

  // 发布传感器数据
  sendData(sensorData) {
    const payload = {
      id: Date.now(),
      params: sensorData,
      method: "thing.event.property.post"
    };
    
    return new Promise((resolve, reject) => {
      try {
        this.publish(this.topics.propertyPost, JSON.stringify(payload));
        resolve();
      } catch (error) {
        reject(error);
      }
    });
  }

  // 发送阈值数据（现在统一作为传感器数据发送）
  sendThreshold(sensor, value) {
    console.log('发送阈值设置:', sensor, value);
    return this.sendData({
      [sensor]: value
    });
  }

  // 心跳相关方法
  startHeartbeat() {
    console.log('启动MQTT心跳, 间隔:', this.keepAliveTime, '秒');
    this.stopHeartbeat(); // 先停止之前的心跳
    
    this.keepAliveInterval = setInterval(() => {
      if (this.isConnected && this.socketTask) {
        this.sendPingReq();
      }
    }, this.keepAliveTime * 1000);
  }

  stopHeartbeat() {
    if (this.keepAliveInterval) {
      clearInterval(this.keepAliveInterval);
      this.keepAliveInterval = null;
    }
    if (this.pingTimeout) {
      clearTimeout(this.pingTimeout);
      this.pingTimeout = null;
    }
  }

  sendPingReq() {
    if (!this.socketTask || !this.isConnected) {
      return;
    }

    console.log('发送MQTT PINGREQ');
    this.lastPingTime = Date.now();
    
    // PINGREQ 包格式: [0xC0, 0x00]
    const pingPacket = new Uint8Array([0xC0, 0x00]);
    
    this.socketTask.send({
      data: pingPacket.buffer
    });

    // 设置ping超时检查（10秒超时）
    this.pingTimeout = setTimeout(() => {
      console.error('PING超时，连接可能异常');
      this.handleConnectionLost();
    }, 10000);
  }

  handlePingResp(packet) {
    console.log('收到MQTT PINGRESP');
    if (this.pingTimeout) {
      clearTimeout(this.pingTimeout);
      this.pingTimeout = null;
    }
  }

  handleConnectionLost() {
    console.log('检测到连接丢失，尝试重连');
    this.isConnected = false;
    this.stopHeartbeat();
    
    if (this.connectionCallback) {
      this.connectionCallback(false);
    }
    
    // 触发自动重连
    if (this.autoReconnect) {
      this.scheduleReconnect();
    }
  }

  // 重连相关方法
  scheduleReconnect() {
    if (this.reconnectInterval) {
      return; // 已经在重连队列中
    }

    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.error('达到最大重连次数，停止重连');
      return;
    }

    this.reconnectAttempts++;
    const delay = this.reconnectDelay * Math.min(this.reconnectAttempts, 5); // 指数退避，最大延迟25秒

    console.log(`计划在 ${delay/1000} 秒后进行第 ${this.reconnectAttempts} 次重连`);

    this.reconnectInterval = setTimeout(() => {
      this.reconnectInterval = null;
      this.reconnect();
    }, delay);
  }

  reconnect() {
    if (this.isConnected) {
      return;
    }

    console.log('尝试重新连接MQTT...');
    this.connect().catch(error => {
      console.error('重连失败:', error.message);
      // 重连失败会自动触发下一次重连
    });
  }

  stopReconnect() {
    if (this.reconnectInterval) {
      clearTimeout(this.reconnectInterval);
      this.reconnectInterval = null;
    }
  }

  disconnect() {
    this.autoReconnect = false; // 手动断开时禁用自动重连
    this.stopReconnect();
    this.stopHeartbeat();
    
    if (this.socketTask) {
      this.socketTask.close();
      this.socketTask = null;
    }
    this.isConnected = false;
    if (this.connectionCallback) {
      this.connectionCallback(false);
    }
  }
}

// 创建全局实例
const mqttInstance = new AliyunIoTMQTT();

// 导出简化接口
module.exports = {
  connect: () => mqttInstance.connect(),
  disconnect: () => mqttInstance.disconnect(),
  setConnectionCallback: (callback) => mqttInstance.setConnectionCallback(callback),
  setDataCallback: (callback) => mqttInstance.setDataCallback(callback),
  sendData: (data) => mqttInstance.sendData(data),
  sendThreshold: (sensor, value) => mqttInstance.sendThreshold(sensor, value),
  isConnected: () => mqttInstance.isConnected,
  
  // 新增控制方法
  enableAutoReconnect: () => { mqttInstance.autoReconnect = true; },
  disableAutoReconnect: () => { mqttInstance.autoReconnect = false; },
  getReconnectAttempts: () => mqttInstance.reconnectAttempts,
  resetReconnectAttempts: () => { mqttInstance.reconnectAttempts = 0; }
}; 